/**
 * Copyright (c) 2011 ~ 2013 Deepin, Inc.
 *               2011 ~ 2013 jouyouyun
 *
 * Author:      jouyouyun <jouyouwen717@gmail.com>
 * Maintainer:  jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 **/

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
	"io"
)

func getAtom(X *xgb.Conn, name string) xproto.Atom {
	reply, err := xproto.InternAtom(X, false, uint16(len(name)),
		name).Reply()
	if err != nil {
		fmt.Println("getAtom failed:", err)
		panic(err)
	}

	return reply.Atom
}

func readInterger(start int, byteOrder binary.ByteOrder,
	buf []byte) (uint32, int) {
	ret := uint32(0)
	data := bytes.NewBuffer(buf[start:])

	binary.Read(data, byteOrder, &ret)

	return ret, 4
}

func readString2(buf io.Reader, order binary.ByteOrder) (string, int) {
	var nameLen uint16
	var d int
	binary.Read(buf, order, &nameLen)
	d += int(nameLen)

	nameBuf := make([]byte, nameLen)
	binary.Read(buf, order, &nameBuf)
	leftPad := 3 - (nameLen+3)%4
	buf.Read(make([]byte, leftPad))
	d += int(leftPad)
	return string(nameBuf), d
}

func readHeader(start int, byteOrder binary.ByteOrder,
	buf []byte) (byte, string, uint32, int) {
	var sType byte
	var d int

	data := bytes.NewBuffer(buf[start:])
	binary.Read(data, byteOrder, start)
	d += 1
	data.Read(make([]byte, 1))
	d += 1
	name, d1 := readString2(data, byteOrder)
	d += d1
	lastSerial, _ := readInterger(start+d, byteOrder, buf)
	d += 4

	return sType, name, lastSerial, d
}

func main() {
	X, err := xgb.NewConn()
	if err != nil {
		fmt.Println("Unable to connect X server:", err)
		panic(err)
	}

	s, err := xproto.GetSelectionOwner(X,
		getAtom(X, "_XSETTINGS_S0")).Reply()
	if err != nil {
		fmt.Println("Own XSettings_S0 Failed:", err)
		panic(err)
	}

	reply, err := xproto.GetProperty(X, false, s.Owner,
		getAtom(X, "_XSETTINGS_SETTINGS"),
		getAtom(X, "_XSETTINGS_SETTINGS"),
		0, 10240).Reply()
	if err != nil {
		fmt.Println("Get Property Failed:", err)
		panic(err)
	}

	l := reply.ValueLen
	data := reply.Value[:l]
	var byteOrder binary.ByteOrder
	if data[0] == 1 {
		byteOrder = binary.BigEndian
	} else {
		byteOrder = binary.LittleEndian
	}

	start := 4
	serial, _ := readInterger(start, byteOrder, data)
	start += 4
	numSettings, _ := readInterger(start, byteOrder, data)
	start += 4

	fmt.Println("serial:", serial, "\tnumSettings:", numSettings)

	for i := uint32(0); i < numSettings; i++ {
		sType, name, _, d := readHeader(start, byteOrder, data)
		start += d
		fmt.Println("name: ", name)
		switch sType {
		case 0:
			v, _ := readInterger(start, byteOrder, data)
                        fmt.Println("v:", v)
			start += 4
		case 1:
			// readString
		case 2:
			// readColor
		}
	}
}
